package com.chris.core.socket.netty.handler;

import com.chris.core.socket.netty.dto.NettyAttributeMapDTO;
import com.chris.core.socket.netty.dto.SocketChannelMapDTO;
import com.chris.core.socket.netty.dto.protocol.CmdObjectProtocol;
import com.chris.core.socket.netty.dto.protocol.FileMessageProtocol;
import com.chris.core.socket.netty.util.NettyRunTimeUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.DefaultEventLoopGroup;
import io.netty.util.Attribute;
import io.netty.util.concurrent.EventExecutorGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;

import static com.chris.core.socket.netty.util.NettyRunTimeUtil.*;

/**
 * 对象处理器 - 服务端
 * 注意：此方法仅能 java netty 客户端 对 java netty 服务端
 * 苏斌 2022-3-29
 */
@Deprecated
public class ObjectServerHandler extends ChannelInboundHandlerAdapter {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * Handler异步线程池，有于本hanlder重负载操作
     */
    private final static EventExecutorGroup executoGroup = new DefaultEventLoopGroup(100);

    /**
     * channel被加入事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //  super.handlerAdded(ctx);


        Channel channel = ctx.channel();

        //--------------处理Attribute-------------------
        Attribute<NettyAttributeMapDTO> attr = channel.attr(NETTY_CHANNEL_KEY);
        NettyAttributeMapDTO attribute = attr.get();
        if (attribute == null) {
            String uuid = UUID.randomUUID().toString();
            //------------放入Attribute
            NettyAttributeMapDTO dto = new NettyAttributeMapDTO(uuid,"NettySocket");
            attribute = attr.setIfAbsent(dto);
            //-------------放入ChannelMap-------------------
            SocketChannelMapDTO socketChannelMap = new SocketChannelMapDTO(uuid,"NettySocket", channel);
            SocketChannelMap.put(uuid, socketChannelMap);
            //--------------
            addOnlineCount();
            log.debug("客户端["+uuid+"]新增 地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
        } else {

        }
        //----------------------------------------------------

    }

    /**
     * 客户端数据读取完毕
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // super.channelReadComplete(ctx);
        //  ctx.writeAndFlush(Unpooled.copiedBuffer("服务端读取完毕\r\n".getBytes(StandardCharsets.UTF_8)));
    }



    /**
     * 文件读取
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // NettyAttributeMapDTO attribute = getAttribute(ctx.channel());
        //log.debug("获取客户端["+attribute.getId()+"]发送数据：" +dto.getMsg());
        if (msg instanceof byte[]) {
            log.debug("收到字节码：" + ((byte[])msg).toString());
        }else if (msg instanceof Long) {
            log.debug("收到Long：" + msg.toString());
        } else if (msg instanceof Double) {
            log.debug("Double：" + msg.toString());
        } else if (msg instanceof Integer) {
            log.debug("收到int：" + msg.toString());
        }  else if (msg instanceof String) {
            log.debug("收到文本：" + msg.toString());
        } else if (msg instanceof CmdObjectProtocol) {
            CmdObjectProtocol dto = (CmdObjectProtocol) msg;
            if (dto.getCode().equals("msg")) {
                log.debug("获取客户端推送数据：" + dto.getMsg());
            } else if (dto.getCode().equals("sendfile") || dto.getCode().equals("revicefile")) {
                log.debug("传输文件:" + dto.getMsg());
            }
        } else if (msg instanceof FileMessageProtocol) {
           // if ( ((FileMessageProtocol) msg).getFileData().length>1024*100)
           //     throw  new Exception("接收数据包操作限制");
            // 重负载IO , 异步执行 read 内容
            executoGroup.execute(new Runnable() {
                @Override
                public void run() {
                    NettyRunTimeUtil.doTransfer((FileMessageProtocol) msg, NettyRunTimeUtil.uploadFilePath, ctx.channel());
                }
            });
            /*
            // 重负载IO , 异步执行 read 内容
            ctx.channel().eventLoop().execute(new Runnable() {
                @Override
                public void run() {
                    UploadFileHandler.doTransfer((FileDataDTO)msg, NettyRunTimeUtil.uploadFilePath,ctx);
                }
            });

             */
        }

        /*
        //方法2 自定义 线程池
        executoGroup.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                //---------------


                //-------------
                return null;
            }
        });*/
//传递给下一个pinline
        super.channelRead(ctx,msg);
    }


    /**
     * 异常处理
     * 一般是关闭通道
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        log.debug("服务端通道捕获异常 客户端地址:"+ctx.channel().remoteAddress() +" 问题:"+cause.toString() )  ;
    }

    /**
     * 当通道就绪
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        // super.channelActive(ctx);
        // channel.writeAndFlush("全局通知-》有客户端上线：地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
      //  channel.writeAndFlush("欢迎上线!\r\n");
        CmdObjectProtocol dto = new CmdObjectProtocol("msg","欢迎上线!");
        ctx.writeAndFlush(dto);

        NettyAttributeMapDTO attribute = getAttribute(ctx.channel());
        log.debug("客户端上线 地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
    }

    /**
     * 通道非活动状态
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //super.channelInactive(ctx);
        Channel channel = ctx.channel();
        NettyAttributeMapDTO dto= getAttribute(channel);
        // super.channelActive(ctx);
        // channels.writeAndFlush("全局通知-》有客户端下线：地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
        log.debug("客户端["+dto.getId()+"]下线 地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
    }

    /**
     * channel被移除
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // super.handlerRemoved(ctx);
        Channel channel = ctx.channel();

        //加入全局数组 ，不需要remove ,自动完成了 remove动作了
        //channels.remove(channel);

        NettyAttributeMapDTO attribute = getAttribute(channel);
        if (attribute != null) {
            SocketChannelMap.remove(attribute.getId());
            //--------------
            subOnlineCount();
            log.debug("客户端["+attribute.getId()+"]离开 地址："+ctx.channel().remoteAddress()+ " 总客户端数："+getOnlineCount());
        }

    }

    /**
     * 获取Channel绑定信息
     * @param channel
     * @return
     */
    public NettyAttributeMapDTO getAttribute(Channel channel)
    {
        Attribute<NettyAttributeMapDTO> attr = channel.attr(NETTY_CHANNEL_KEY);
        NettyAttributeMapDTO attribute = attr.get();
        return attribute;
    }
}
